package com.oig.sys.auth.service.impl;

import cn.hutool.core.util.StrUtil;
import com.oig.common.constants.CommonEnum;
import com.oig.common.exception.BadRequestException;
import com.oig.common.module.SysRequest;
import com.oig.sys.auth.dao.ITbJobDao;
import com.oig.sys.auth.dto.JobDto;
import com.oig.sys.auth.entity.TbJob;
import com.oig.sys.auth.service.ITbDepartmentService;
import com.oig.sys.auth.service.ITbJobRoleService;
import com.oig.sys.auth.service.ITbJobService;
import com.oig.sys.auth.service.ITbUserJobService;
import com.oig.sys.auth.vo.DepartmentVo;
import com.oig.sys.auth.vo.JobVo;
import com.oig.sys.security.util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * @author wuxl
 */
@Service
@Slf4j
public class TbJobServiceImpl implements ITbJobService {

	private final ITbJobDao tbJobDao;
	private final ITbJobRoleService jobRoleService ;
	private final ITbUserJobService userJobService ;
	private final ITbDepartmentService departmentService ;

	@Autowired
	public TbJobServiceImpl(ITbJobDao tbJobDao,
							ITbJobRoleService jobRoleService,
							ITbUserJobService userJobService,
							ITbDepartmentService departmentService){
		 this.tbJobDao = tbJobDao;
		 this.jobRoleService = jobRoleService;
		 this.userJobService = userJobService;
		 this.departmentService = departmentService ;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public JobVo addJob(JobDto jobDto) {
		log.debug("job dto:{}",jobDto);
		TbJob job = new TbJob();
		BeanUtils.copyProperties(jobDto,job,"id");
		if (jobDto.getTenantId()==0){
			throw new BadRequestException("请选择租户，所属租户id不能为0") ;
		}
		this.checkData(job);
		job.setCreateUserId(SecurityUtil.getDefineUserMain().getId());
		job.setCreateUserName(SecurityUtil.getDefineUserMain().getRealName());
		job.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		job.setCreateTime(new Date());
		this.tbJobDao.save(job) ;
		JobVo jobVo = new JobVo();
		if (jobDto.getRoleList()!=null && !jobDto.getRoleList().isEmpty()){
			jobVo.setRoleList(jobRoleService.addJobRole(job, jobDto.getRoleList()));
		}
		BeanUtils.copyProperties(job, jobVo);
		return jobVo;
	}


	private void checkRole(TbJob job){
		if (job==null){
			throw new BadRequestException("岗位id错误") ;
		}
		if (SecurityUtil.getDefineUserMain().getTenantId()!=0){
			if (!job.getTenantId().equals(SecurityUtil.getDefineUserMain().getTenantId())){
				throw new BadRequestException("无租户权限");
			}
		}
	}

	private void checkData(TbJob job){
		DepartmentVo departmentVo = departmentService.getDepartment(job.getDepartId()) ;
		if (!job.getTenantId().equals(departmentVo.getTenantId())){
			throw new BadRequestException("部门所属租户和岗位所属公司不匹配") ;
		}
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public JobVo updateJob(JobDto jobDto) {
		if (jobDto.getTenantId()==0){
			throw new BadRequestException("请选择租户，所属租户id不能为0") ;
		}
		TbJob job = this.tbJobDao.getTbJobById(jobDto.getId()) ;
		log.debug("job dto:{}, entity:{}",jobDto, job);
		this.checkRole(job);
		this.checkData(job);
		BeanUtils.copyProperties(jobDto, job,"id","status");
		job.setLastUpdateId(SecurityUtil.getDefineUserMain().getId());
		job.setLastUpdateName(SecurityUtil.getDefineUserMain().getRealName());
		job.setLastUpdateTime(new Date());
		this.tbJobDao.save(job) ;
		JobVo jobVo = new JobVo();
		if (jobDto.getRoleList()!=null && !jobDto.getRoleList().isEmpty()){
			jobVo.setRoleList(jobRoleService.updateJobRole(job, jobDto.getRoleList()));
		}
		BeanUtils.copyProperties(job, jobVo);
		return jobVo;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void cancelJob(Integer jobId) {
		TbJob job = this.tbJobDao.getTbJobById(jobId) ;
		this.checkRole(job);
		job.setStatus(CommonEnum.CommonStatusEnum.DEL.getCode());
		this.tbJobDao.save(job) ;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void revertJob(Integer jobId) {
		TbJob job = this.tbJobDao.getTbJobById(jobId) ;
		this.checkRole(job);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(job.getStatus())){
			throw new BadRequestException("岗位非注销状态") ;
		}
		job.setStatus(CommonEnum.CommonStatusEnum.OK.getCode());
		this.tbJobDao.save(job) ;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void delJob(Integer jobId) {
		TbJob job = this.tbJobDao.getTbJobById(jobId) ;
		this.checkRole(job);
		if (!CommonEnum.CommonStatusEnum.DEL.getCode().equals(job.getStatus())){
			throw new BadRequestException("只有注销状态才能物理删除") ;
		}
		this.jobRoleService.delJobRoleByJobId(jobId);
		this.userJobService.delByJobId(jobId);
		this.tbJobDao.delete(job);
	}

	@Override
	public List<JobVo> listAllJob(SysRequest<JobDto> jobRequest) {
		Sort sort = null;
		if (StrUtil.isNotBlank(jobRequest.getSortColumn())) {
			sort = Sort.by(CommonEnum.SortEnum.DESC.getCode().equals(jobRequest.getSort())?Sort.Direction.DESC:Sort.Direction.ASC,jobRequest.getSortColumn()) ;
		}
		List<TbJob> jobList;
		Specification<TbJob> specification = new Specification<TbJob>() {
			@Override
			@Nullable
			public Predicate toPredicate(@NonNull Root<TbJob> root, @NonNull CriteriaQuery<?> criteriaQuery, @NonNull CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicateList = new ArrayList<>();
				if (jobRequest.getParamDto().getDepartId() != null) {
					Path<Integer> departIdPath = root.get("departId");
					predicateList.add(criteriaBuilder.equal(departIdPath, jobRequest.getParamDto().getDepartId()));
				}
				if (StrUtil.isNotBlank(jobRequest.getParamDto().getJobName())) {
					Path<String> jobNamePath = root.get("jobName");
					predicateList.add(criteriaBuilder.like(jobNamePath, "%" + jobRequest.getParamDto().getJobName() + "%"));
				}
				if (StrUtil.isNotBlank(jobRequest.getParamDto().getStatus())){
					log.debug("query job status={}",jobRequest.getParamDto().getStatus());
					Path<String> statusPath = root.get("status");
					predicateList.add(criteriaBuilder.equal(statusPath, jobRequest.getParamDto().getStatus()));
				} else {
					Path<String> statusPath = root.get("status");
					predicateList.add(criteriaBuilder.equal(statusPath, CommonEnum.CommonStatusEnum.OK.getCode()));
				}
				Path<Integer> tenantIdPath = root.get("tenantId");
				predicateList.add(criteriaBuilder.equal(tenantIdPath, jobRequest.getParamDto().getTenantId()));
				criteriaQuery.where(predicateList.toArray(new Predicate[0]));
				return criteriaQuery.getRestriction();
			}
		};
		if (sort == null) {
			jobList = this.tbJobDao.findAll(specification);
		} else {
			jobList = this.tbJobDao.findAll(specification, sort);
		}
		List<JobVo> jobVoList = new ArrayList<>();
		for (TbJob job : jobList){
			JobVo jobVo = new JobVo();
			BeanUtils.copyProperties(job,jobVo);
			jobVoList.add(jobVo);
		}
		return jobVoList;
	}


	@Override
	public JobVo getJobInfo(Integer jobId) {
		JobVo jobVo = this.tbJobDao.getVoById(jobId);
		if (jobVo==null){
			throw new BadRequestException("岗位id错误") ;
		}
		jobVo.setRoleList(this.jobRoleService.getJobRole(jobId));
		return jobVo;
	}
}
